package com.utils.excel;

import com.utils.WebUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

public class ExcelUtils {

    /**
     * 传入数据，创建excel文件
     * @param type 文件的类型（xls、xlsx）
     * @param path 保存的文件夹路径
     * @param headers 数据的表头
     * @param data 数据二维数组
     * @param filename 文件名
     * @return 返回整个路径名称
     */
    public static String createExcel(String type, String path, String[] headers,
                                   Object[][] data, String filename) throws IOException {
        if (type == null || path == null) return null;
        File file = new File(path);
        if (!file.exists()) file.mkdirs();//文件路径不存在，就创建

        //根据传入的类型创建对应的格式
        Workbook workbook = null;
        if (type.equals("xls"))
            workbook = new HSSFWorkbook();
        else if (type.equals("xlsx"))
            workbook = new XSSFWorkbook();
        else
            return null;
        //创建表头
        //1.创建sheet表单
        Sheet sheet = workbook.createSheet();
        //2.通过表单创建第一行的表头
        Row headerRow = sheet.createRow(0);
        //3.循环加入每一个单元格
        for (int i = 0; i < headers.length; i++) {
            //循环设置每一列
            headerRow.createCell(i).setCellValue(headers[i]);
        }

        //有多少行
        for (int i = 1; i <= data.length; i++) {
            //创建除了第一行的每一行
            Row row = sheet.createRow(i);
            //创建每一列
            for (int j = 0; j < data[i-1].length; j++) {
                //创建每一行的每一列
                row.createCell(j).setCellValue(data[i-1][j]==null?"":data[i-1][j].toString());
            }
        }

        filename += ".xls";
        if (workbook instanceof XSSFWorkbook) {
            filename += "x";//如果是操作xlsx对量的类，就在后缀中加一个x
        }
        path += "/"+filename;
        //将创建好的内容写入到磁盘中
        OutputStream out = new FileOutputStream(new File(path));
        workbook.write(out);
        out.close();
        return path;
    }


    /**
     * 将list集合的数据转化成二维数组
     * @param clas 反射
     * @param list 对象数据的集合
     * @return 数据二维数组
     */
    public static Object[][] listToArrs(Class clas, List list) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        //1.通过反射获取所有的字段
        Field[] fields = clas.getDeclaredFields();
        //2.得到字段的所有数量并创建每一行数据的长度
        Object[][] data = new Object[list.size()][fields.length];
        //3.获取每一个对象的每一个字段的值
        for (int i = 0; i < list.size(); i++) {
            //得到list每一个对象
            Object obj = list.get(i);
            //得到每一列
            for (int j = 0; j < fields.length; j++) {
                //得到每一列的值
                //得到每一个字段的类型
                Field field = fields[j];
                //拼接方法名
                String fieldName = field.getName();
                String methodName = "get" + fieldName.substring(0,1).toUpperCase()
                        + fieldName.substring(1);
                //得到方法
                Method method = clas.getDeclaredMethod(methodName);
                //调用方法，得到对应的值
                Object value = method.invoke(obj);
                //将值存入二维数组
                data[i][j] = value;
            }
        }
        return data;
    }


    /**
     * 读取excel并存入到一个list集合
     * @param clas
     * @param path
     * @param <T>
     * @return
     */
    public static <T> List<T> readExcel(Class<T> clas, String path){
        File file = new File(path);
        if (!file.exists()) return null;//文件不存在，直接结束
        List<T> tList = new ArrayList<>();
        try {
            //通过反射获取所有的字段
            Field[] fields = clas.getDeclaredFields();
            //获取Workbook
            Workbook workbook = WorkbookFactory.create(file);
            //获取第一个sheet
            Sheet sheet = workbook.getSheetAt(0);
            //获取所有的物理（实际写过内容的行）行
            int rowNums = sheet.getPhysicalNumberOfRows();
            //循环遍历所有的行
            for (int i = 1; i < rowNums; i++) {
                //通过反射创建一个新的对象
                T obj = clas.newInstance();

                //获取具体的每一行Row:行
                Row row = sheet.getRow(i);
                //获取每一行所有的列 Cell:单元格
                int cellNums = row.getPhysicalNumberOfCells();
                //循环遍历每一行所有的列
                for (int j = 0; j < cellNums; j++) {
                    //获取某一行某一列
                    Cell cell = row.getCell(j);
                    //得到单元格的数据
                    Object value = parseValue(cell);
                    //得到每一个字段的名称
                    String fieldName = fields[j].getName();
                    //拼接set方法
                    String setMethod = "set" + fieldName.substring(0,1).toUpperCase()
                            + fieldName.substring(1);
                    //通过反射获取方法
                    Method method = clas.getDeclaredMethod(setMethod,fields[j].getType());
                    //给每一个对象设置
                    method.invoke(obj, WebUtils.reverseValue(value==null?"":value.toString(), fields[j].getType().getSimpleName()));
                }
                tList.add(obj);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return tList;
    }

    /**
     * 将单元格的数据解析并返回
     * @param cell
     * @return
     */
    public static Object parseValue(Cell cell){
        Object value = null;
        switch (cell.getCellTypeEnum()) {
            case STRING:
                value = cell.getStringCellValue();
                break;
            case NUMERIC:
                //判断这个数字类型到底是不是时间类型。参数：传入一个单元格
                if (DateUtil.isCellDateFormatted(cell)) {
                    value = cell.getDateCellValue();
                } else {
                    value = cell.getNumericCellValue();
                }
                break;
            case FORMULA:
                value = cell.getCellFormula();
                break;
            case ERROR:
                value = cell.getErrorCellValue();
                break;
            case BOOLEAN:
                value = cell.getBooleanCellValue();
                break;
            case BLANK:
                value = "";
                break;
            default:
                break;
        }
        return value;
    }



}
